import { _decorator, Component, Node, UITransform, Vec3, Vec2, RigidBody2D, v2, BoxCollider2D, ERigidBody2DType, Label } from 'cc';
import { GlobalAttribute } from './SingletonPattern/GlobalAttribute';
import { easyrandomBox } from './easyrandomBox';

const { ccclass, property } = _decorator;

@ccclass('pushBoxTs')
export class pushBoxTs extends Component {
    //先从单例里获取他的实例
    Global: GlobalAttribute;

    //注册这个脚本的刚体
    rigidBody: RigidBody2D = null;
    //初始化点击后的位置
    lastTouchPosition: Vec2 = new Vec2();
    targetPosition: Vec2 = new Vec2();
    //这个脚本上元素初始位置
    easyrandomBoxTs;
    InitPos;
    //检测拖动，如果是拖动的元素就打开，让它的状态变得跟被推的不一样
    dragBool: Boolean = false;
    colliderBool: Boolean = false;
    newPosition;
    child;
    nodepos;
    moveDirectX: Boolean = false;
    moveDirectY: Boolean = false;
    boxnumber;
    initarrpos = {
        x: null,
        y: null
    };
    deltaX;
    deltaY;
    bool;
    recognition;
    collider;
    parentUITransform;
    onLoad() {
        this.recognition = false;
        this.Global = GlobalAttribute.getInstance();
        this.easyrandomBoxTs = this.node.parent.getComponent(easyrandomBox);
        this.child = this.node.parent.children;
        this.nodepos = this.node.position;
        this.rigidBody = this.getComponent(RigidBody2D);
        this.collider = this.node.getComponent(BoxCollider2D);
        this.parentUITransform = this.node.parent.getComponent(UITransform);
        // 监听元素B的位置变化
        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
        if (this.collider) {
            this.collider.friction = 0;
            this.collider.density = 10;
            this.collider.apply();
        }
    }

    start() {
        //开局把自身的节点位置保存起来随时使用，如果遇到更改的时候修改就行了
        this.InitPos = this.nodepos.clone()
        this.boxnumber = this.easyrandomBoxTs.blockNumber;

    }

    onTouchStart(event) {
        this.recognition = true;
        this.Global.addNode = this.node;
        if (this.Global.getNodeArrPos.length == 0) {
            this.Global.addNode = this.node;
        }

        this.bool = false;
        let directionArrX = this.child.filter(e => e.position.x == this.nodepos.x);
        let directionArrY = this.child.filter(e => e.position.y == this.nodepos.y);

        if (directionArrX.length == this.boxnumber) {
            this.moveDirectX = true;
        }

        if (directionArrY.length == this.boxnumber) {
            this.moveDirectY = true;
        }

        this.Global.setthisnode = this.node;
        this.colliderBool = true;
        this.setInitXYBox(2);

        const touchPosition = event.getUILocation();
        
        const newPosition = this.parentUITransform.convertToNodeSpaceAR(new Vec3(touchPosition.x, touchPosition.y, 0));
        this.lastTouchPosition.set(newPosition.x, newPosition.y);
        this.targetPosition.set(newPosition.x, newPosition.y);

    }

    filterXY;

    setInitXYBox(group) {
        //获取此元素在二维数组中的位置
        let initarrpos = this.initarrpos;
        let arr = this.easyrandomBoxTs;

        // 仅当newarr为空时，添加初始化位置的元素
        if (arr.newarr.length === 0) {
            this.setGroup(arr.initarr[initarrpos.x][initarrpos.y], group);
            arr.newarr.push(arr.initarr[initarrpos.x][initarrpos.y]);
        }

        if (arr.initarr.length > 0) {

            for (let i = 0; i < arr.initarr.length; i++) {
                let xNode = arr.initarr[initarrpos.x][i];
                let yNode = arr.initarr[i][initarrpos.y];

                // 检查是否已经存在相同的 x, y 位置
                let xPosExists = arr.newarr.some(e => e.x == initarrpos.x && e.y == i);
                let yPosExists = arr.newarr.some(e => e.y == initarrpos.y && e.x == i);

                if (!xPosExists) {
                    this.setGroup(xNode, group);
                    arr.newarr.push(xNode);
                }
                if (!yPosExists) {
                    this.setGroup(yNode, group);
                    arr.newarr.push(yNode);
                }
            }
        }

    }

    setGroup(e, group) {

        if (e && e.node && e.node.name) {
            // console.log(e);

            let childrigidBody = e.node.getComponent(RigidBody2D);
            let childboxCollider = e.node.getComponent(BoxCollider2D);

            if (childrigidBody && childboxCollider) {
                childrigidBody.group = group;
                childboxCollider.group = group;
            }

            // 确保刚体组件存在

            let rigidBody = e.node.getComponent(RigidBody2D);
            if (rigidBody) {
                // 将刚体类型从 Static 改为 Dynamic
                rigidBody.type = ERigidBody2DType.Dynamic;
            }
        }
    }

    setColliderGroup() {
        let thisNodeDirectiony = Math.abs(this.nodepos.y - this.InitPos.y);
        let thisNodeDirectionx = Math.abs(this.nodepos.x - this.InitPos.x);

        const updateGroups = (directionCheck, isXDirection, group) => {
            for (let i = 0; i < this.easyrandomBoxTs.newarr.length; i++) {

                const element = this.easyrandomBoxTs.newarr[i].node;
                if (element && element.name) {

                    let Direction = isXDirection
                        ? Math.abs(element.position.x - this.nodepos.x)
                        : Math.abs(element.position.y - this.nodepos.y);

                    if (Direction > directionCheck) {
                        let childrigidBody = element.getComponent(RigidBody2D);
                        let childboxCollider = element.getComponent(BoxCollider2D);

                        if (childrigidBody.group !== group) {
                            childrigidBody.group = group;
                            childboxCollider.group = group;
                        }
                    }
                }
            }
        };

        if (thisNodeDirectiony > 30 && this.Global.moveDirection == 'y') {
            updateGroups(30, true, 2);
        } else if (thisNodeDirectiony < 30 && thisNodeDirectiony > 5 && this.Global.moveDirection == 'y') {
            updateGroups(30, true, 2);
        } else if (thisNodeDirectionx > 30 && this.Global.moveDirection == 'x') {
            updateGroups(30, false, 2);
        } else if (thisNodeDirectionx < 30 && thisNodeDirectionx > 5 && this.Global.moveDirection == 'x') {
            updateGroups(30, false, 2);
        }
    }

    onTouchMove(event) {
        if (this.Global.getNodeArrPos.length == 0) {
            this.Global.addNode = this.node;
        }
    
        this.dragBool = true;
        const touchPosition = event.getUILocation();
        const newPosition = this.parentUITransform.convertToNodeSpaceAR(new Vec3(touchPosition.x, touchPosition.y, 0));
        this.newPosition = newPosition;
        const deltaX = Math.abs(newPosition.x - this.InitPos.x);
        const deltaY = Math.abs(newPosition.y - this.InitPos.y);
    
        const nearOriginThreshold = 10;
        if (deltaX < nearOriginThreshold && deltaY < nearOriginThreshold) {
            this.Global.moveDirection = null;
        }
    
        if (this.Global.moveDirection === null) {
            this.Global.moveDirection = deltaX > deltaY ? 'x' : 'y';
        }
        const moveDirection = this.Global.moveDirection;
        let force;
        const mass = this.rigidBody.getMass();
        this.rigidBody.linearDamping = 2;
    
        if (this.collider) {
            this.collider.friction = 0;
            this.collider.density = 20;
            this.collider.apply();
        }
    
        const applyForce = (deltaPosition: Vec2) => {
            force = deltaPosition.multiplyScalar(mass * 30);
            this.rigidBody.applyForceToCenter(new Vec2(force.x, force.y), true);
        };
    
        const updatePosition = (newPos: Vec3, initPos: Vec3) => {
            this.node.setPosition(newPos.x, newPos.y, 0);
        };
    
        if (moveDirection === 'x' && !this.moveDirectY) {
            const deltaPosition = new Vec2(newPosition.x - this.lastTouchPosition.x, 0);
            applyForce(deltaPosition);
            this.lastTouchPosition.set(newPosition.x, newPosition.y);
            this.targetPosition.set(newPosition.x, this.InitPos.y);
    
            if (Math.abs(this.nodepos.y - this.InitPos.y) > 0.5) {
                updatePosition(new Vec3(newPosition.x, this.InitPos.y, 0), this.InitPos);
            }
        } else if (moveDirection === 'y' && !this.moveDirectX) {
            const deltaPosition = new Vec2(0, newPosition.y - this.lastTouchPosition.y);
            applyForce(deltaPosition);
            this.lastTouchPosition.set(newPosition.x, newPosition.y);
            this.targetPosition.set(this.InitPos.x, newPosition.y);
    
            if (Math.abs(this.nodepos.x - this.InitPos.x) > 0.5) {
                updatePosition(new Vec3(this.InitPos.x, newPosition.y, 0), this.InitPos);
            }
        }
    
        if (moveDirection !== this.Global.moveDirection) {
            this.Global.moveDirection = moveDirection;
        }
    
        this.rigidBody.wakeUp();
        const distancex = this.nodepos.x - this.InitPos.x;
        const distancey = this.nodepos.y - this.InitPos.y;
        const previousDirection = this.easyrandomBoxTs.Direction;
    
        if (moveDirection === 'x') {
            this.easyrandomBoxTs.Direction = distancex > 1 ? 'right' : 'left';
        } else if (moveDirection === 'y') {
            this.easyrandomBoxTs.Direction = distancey > 1 ? 'up' : 'down';
        }
    
        if (Math.abs(distancex) < 1 && Math.abs(distancey) < 1) {
            this.easyrandomBoxTs.Direction = '';
        }
    
        if (previousDirection !== this.easyrandomBoxTs.Direction) {
            console.log('更改方向');
            this.Global.clearNodeArr();
            if (this.Global.getNodeArrPos.length == 0) {
                this.Global.addNode = this.node;
            }
            this.setInitXYBox(2);
            this.bool = false;
            this.easyrandomBoxTs.newarr.forEach(e => this.setGroup(e, 2));
        }
    
        this.setArrNodes(distancex, distancey, previousDirection);
    }
    
    setArrNodes(x, y, bool) {
        if ((Math.abs(x) > 10 || Math.abs(y) > 10) && !this.bool) {
            this.addArrNode(bool);
            this.setNewArrType();
        }
    }

    // 从这19个元素中筛选需要放进nodeArr的元素
    addArrNode(boolDirection) {
        let that = this;
        let node;
        let randomboxts = that.easyrandomBoxTs;

        function inNodeArr(e) {
            for (let i = 1; i < randomboxts.newarr.length; i++) {
                let thisarrposx = that.initarrpos.x;
                let thisarrposy = that.initarrpos.y;
                if (e == 'up' && Number(thisarrposy + i) < 10) {

                    node = randomboxts.initarr[thisarrposx][thisarrposy + i].node;

                } else if (e == 'down' && Number(thisarrposy - i) > 0) {

                    node = randomboxts.initarr[thisarrposx][thisarrposy - i].node;

                } else if (e == 'left' && Number(thisarrposx - i) > 0) {

                    node = randomboxts.initarr[thisarrposx - i][thisarrposy].node;

                } else if (e == 'right' && Number(thisarrposx + i) < 10) {

                    node = randomboxts.initarr[thisarrposx + i][thisarrposy].node;

                }

                if (node == undefined || !node || node.name == '') break;
                that.Global.addNode = node;
                //把已经放进去的元素的属性改为true代表已经放入数组
                node.getComponent(pushBoxTs).recognition = true;

            }

        }

        if (boolDirection == 'up') {

            inNodeArr(boolDirection);

        } else if (boolDirection == 'down') {

            inNodeArr(boolDirection);

        } else if (boolDirection == 'left') {

            inNodeArr(boolDirection);

        } else if (boolDirection == 'right') {

            inNodeArr(boolDirection);

        }
        this.bool = true;


    }

    setNewArrType() {
        let randomboxts = this.easyrandomBoxTs;
        if (randomboxts.newarr.length == 0) return;
        for (let i = 0; i < randomboxts.newarr.length; i++) {
            const element = randomboxts.newarr[i];
            if (!element.node) continue;

            if (!element.node.getComponent(pushBoxTs).recognition) {

                // 确保刚体组件存在
                let rigidBody = element.node.getComponent(RigidBody2D);
                if (rigidBody) {
                    // 将刚体类型从 Dynamic 改为 Static
                    rigidBody.type = ERigidBody2DType.Static;
                }
            }
        }
    }

    ResetInitPos() {
        const nodeParentChild = this.child;
        for (var i = 0; i < nodeParentChild.length; i++) {
            let pushBoxComponent = nodeParentChild[i].getComponent(pushBoxTs);
            let childRigidBody2D = nodeParentChild[i].getComponent(RigidBody2D);
            let childBoxCollider2D = nodeParentChild[i].getComponent(BoxCollider2D);
            if (nodeParentChild[i] && nodeParentChild[i].getComponent(pushBoxTs).recognition) {
                nodeParentChild[i].getComponent(pushBoxTs).recognition = false;
            }
            if (pushBoxComponent && pushBoxComponent.InitPos) {
                //把我的位置设置为 我的 ts 中的初始位置
                nodeParentChild[i].position = pushBoxComponent.InitPos;
                if (childRigidBody2D.type !== 0) {

                    childRigidBody2D.type = ERigidBody2DType.Static;
                }
                childRigidBody2D.group = 1;
                childBoxCollider2D.group = 1;
            }
        }
    }

    onTouchEnd() {
        this.easyrandomBoxTs.Direction = '';
        this.Global.thisnode = null;
        this.Global.clearotherarr();
        this.dragBool = false;
        this.easyrandomBoxTs.duibi();
        this.Global.moveDirection = null;
        this.ResetInitPos();
        this.moveDirect();
        this.Global.clearNodeArr();
    }

    moveDirect() {
        this.moveDirectX = false;
        this.moveDirectY = false;

    }

    onTouchCancel() {
        this.onTouchEnd();

    }


    update(dt) {

        //让拖动的元素更稳定，不会出现滑行的现象
        if (this.dragBool) {
            //获取当前速度
            const velocity = this.rigidBody.linearVelocity;
            //检查当前的位置是否超过目标位置
            const currentPosition = this.nodepos;
            //获取距离
            const directionToTarget = new Vec2(this.targetPosition.x - currentPosition.x, this.targetPosition.y - currentPosition.y);
            //如果当前速度的方向与目标方向相反
            if (directionToTarget.dot(velocity) < 0) {
                //停止滑行
                this.rigidBody.linearVelocity = v2(0, 0);
            }
            //确保刚体唤醒
            this.rigidBody.wakeUp();
        }

        this.backOtherBoxInitPos();
    }

    //设置除了拖动的元素之外的刚体的移动和移动限制
    backOtherBoxInitPos() {

        if (!this.Global.getthisnode) return;
        let distancex = Math.abs(this.nodepos.x - this.Global.getthisnode.position.x);
        let distancey = Math.abs(this.nodepos.y - this.Global.getthisnode.position.y);

        let initDistancex = Math.abs(this.InitPos.x - this.Global.getthisnode.getComponent(pushBoxTs).InitPos.x);
        let initDistancey = Math.abs(this.InitPos.y - this.Global.getthisnode.getComponent(pushBoxTs).InitPos.y);

        if (this.node === this.Global.getthisnode) return;

        if ((distancex > initDistancex + 1 || distancey > initDistancey + 1) && !this.dragBool) {
            this.moveInitPos();

        }
    }

    //设置刚体的速度，具体可以更改向量乘数里的值，或者更改density刚体质量
    moveInitPos() {
        //计算新的位置和原来位置的距离
        const deltaPosition = new Vec2(this.nodepos.x - this.InitPos.x, this.nodepos.y - this.InitPos.y);
        //防止多余的输出
        if (Math.abs(deltaPosition.x) < 0.5 && Math.abs(deltaPosition.y) < 0.5) return;

        //这个距离的向量乘数
        let force = deltaPosition.multiplyScalar(100);
        //刚体的速度衰减效果
        this.rigidBody.linearDamping = 10;
        //给刚体施加力

        this.rigidBody.applyForceToCenter(new Vec2(-force.x, -force.y), true);
        if (this.collider) {
            this.collider.friction = 0;
            this.collider.density = 10;
            this.collider.apply();
        }
    }

}